package com.lry.proxy;

import com.lry.common.CommonConstants;
import com.lry.router.Router;
import com.lry.spi.LoadLevel;
import com.lry.util.CollectionUtils;
import com.lry.util.StringUtils;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

@LoadLevel(name = "cglib")
public class CglibProxy extends AbstractProxy implements Proxy {

    private Router router;
    private Set<String> excludeMethod = new TreeSet();
    private Set<String> includeMethod = new TreeSet();
    private String group;
    private String version;

    public CglibProxy(Router router,String[] includeMethod,String[] excludeMethod,String group,String version){
        this.router = router;
        this.group = group;
        this.version = version;
        if(CollectionUtils.isNotEmpty(includeMethod)){
            for (String s : includeMethod) {
                this.includeMethod.add(s);
            }
        }
        if(CollectionUtils.isNotEmpty(excludeMethod)){
            for (String s : excludeMethod) {
                this.excludeMethod.add(s);
            }
        }
    }

    @Override
    public <T> T getProxy(Class clazz)   {
        return getProxy(clazz,null);
    }

    @Override
    public <T> T getProxy(Class clazz,String implName)   {
        Enhancer en = new Enhancer();
        en.setSuperclass(clazz);
        en.setCallback(new CglibMethodInterceptor(clazz,implName));
        return (T) en.create();
    }


    private class CglibMethodInterceptor implements MethodInterceptor{

        private Class clazz;
        private String implName;

        public CglibMethodInterceptor(Class clazz,String implName) {
            this.clazz = clazz;
            this.implName = implName;
        }

        @Override
        public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            if(excludeMethod.contains(method.getName())){
                return null;
            }
            if(!includeMethod.isEmpty()&&!includeMethod.contains(method.getName())){
                return null;
            }
            Map<String,Object> att = new HashMap<>();
            if(StringUtils.isNotBlank(implName)){
                att.put(CommonConstants.SPEC_IMPL_NAME_KEY,implName);
            }
            if(StringUtils.isNotBlank(version)){
                att.put(CommonConstants.SPEC_VERSION_KEY,version);
            }
            if(StringUtils.isNotBlank(group)){
                att.put(CommonConstants.SPEC_GROUP_KEY,group);
            }
            return enhance(att,method,args,clazz,router);
        }


    }
}
